/*
	The MIT License (MIT)

	Copyright (c) 2014 abel533@gmail.com

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
 */

package com.california.pay.common.mybatis.page;

import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.BeanUtils;

import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

/**
 * Mybatis - 通用分页拦截器
 *
 * @author liuzh/abel533/isea533
 * @version 3.3.0 项目地址 : http://git.oschina.net/free/Mybatis_PageHelper
 */
@SuppressWarnings({"rawtypes", "unchecked"})
@Intercepts(@Signature(type = Executor.class, method = "query", args = {
        MappedStatement.class, Object.class, RowBounds.class,
        ResultHandler.class}))
public class PageHelper implements Interceptor {
    // sql工具类
    private static SqlUtil SQLUTIL = null;

    /**
     * Mybatis拦截器方法
     *
     * @param invocation 拦截器入参
     * @return 返回执行结果
     * @throws Throwable 抛出异常
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        final Object[] args = invocation.getArgs();

        Page<?> page = null;
        int flag = 0;
        if (args[1] instanceof ParamMap) {
            Set<Entry> entrySet = ((ParamMap) args[1]).entrySet();
            for (Entry entry : entrySet) {
                if (entry.getValue() instanceof Page) {
                    page = (Page<?>) entry.getValue();
                    break;
                }
            }
            flag = 1;
        } else if (((MappedStatement) args[0]).getId().matches(".*Page$")) {
            Integer pageNum = (Integer) BeanUtils.getPropertyDescriptor(args[1].getClass(), "pageNum").getReadMethod().invoke(args[1], new Object[0]);
            Integer pageSize = (Integer) BeanUtils.getPropertyDescriptor(args[1].getClass(), "pageSize").getReadMethod().invoke(args[1], new Object[0]);

            page = new Page(pageNum, pageSize);
            flag = 2;
        }

        if (page != null) {
            // 忽略RowBounds-否则会进行Mybatis自带的内存分页
            args[2] = RowBounds.DEFAULT;
            // 获取原始的ms
            MappedStatement ms = (MappedStatement) args[0];

            SqlSource sqlSource = ms.getSqlSource();
            // 将参数中的MappedStatement替换为新的qs
            SQLUTIL.processCountMappedStatement(ms, sqlSource, args);
            // 查询总数
            Object totalResult = invocation.proceed();
            // 设置总数
            long totalCount = ((Integer) ((List) totalResult).get(0))
                    .longValue();
            page.setTotal(totalCount);
            long totalPage = totalCount / page.getPageSize() + ((totalCount % page.getPageSize() == 0) ? 0 : 1);
            page.setPages(totalPage);
            // 将参数中的MappedStatement替换为新的qs
            SQLUTIL.processPageMappedStatement(ms, sqlSource, page,
                    args);
            // 执行分页查询
            Object list = invocation.proceed();
            // 得到处理结果
            page.setList((List) list);

            //--------------------------
            if (flag == 2) {
                PageList pageList = new PageList();
                pageList.setPageNum(page.getPageNum());
                pageList.setPageSize(page.getPageSize());
                pageList.setStartRow(page.getStartRow());
                pageList.setEndRow(page.getEndRow());
                pageList.setPages(page.getPages());
                pageList.setTotal(page.getTotal());
                if (page.getList() != null) {
                    pageList.addAll(page.getList());
                }

                return pageList;
            } else if (flag == 1) {
                return list;
            }
        }

        // 返回结果
        return invocation.proceed();
    }

    /**
     * 只拦截Executor
     *
     * @param target
     * @return
     */
    @Override
    public Object plugin(Object target) {
        if (target instanceof Executor) {
            return Plugin.wrap(target, this);
        } else {
            return target;
        }
    }

    /**
     * 设置属性值
     *
     * @param p 属性值
     */
    @Override
    public void setProperties(Properties p) {
        String dialect = "mysql";
        SQLUTIL = new SqlUtil(dialect);
    }
}
